package com.supermap.gwfs.datashare.of.service;

import java.awt.geom.Rectangle2D;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSONObject;
import com.supermap.gcpp.core.common.UniObject;
import com.supermap.gwfs.datashare.entity.*;
import com.supermap.gwfs.datashare.param.ResponseData;
import com.supermap.gwfs.datashare.service.GridForecastService;
import com.supermap.gwfs.datashare.service.ServerService;
import com.supermap.gwfs.datashare.service.StationInfoService;
import com.supermap.gwfs.datashare.util.DataFormatUtil;
import com.supermap.gwfs.datashare.util.Logger;
import com.supermap.gwfs.datashare.util.PageData;
import com.supermap.gwfs.datashare.util.ReadXML;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**  
 * @Description: GridData业务
 * @author zhoujian
 * @date 2017-6-19
 * @version V1.0 
 */
@Service
public class GridDataService
{
	private Logger logger = Logger.getLogger(this.getClass());
	@Resource
	private NetcdfService netcdfService;
	@Resource
	private GridForecastService gridForecastService;
	@Resource
	private LoadService loadService;
	@Resource
	private ServerService serverService;
	@Resource
	private StationInfoService stationInfoService;
	@Resource
	private StationDataService stationDataService;
	@Resource
	private WeatherService weatherService;
	
	/**
	 * 
	 * @Description: 读取netcdf文件和裁切数据
	 * @return List<ReturnData>
	 * @throws
	 */
	private ReturnData getGridData(String rootPath , List<Object> gridForecasts , Rectangle2D rectangle2d )
	{
		ReturnData returnData = new ReturnData();
		try
		{
			List<GridData> gridDatas = new ArrayList<GridData>();
			for (Object object : gridForecasts)
			{
				GridForecast gf = (GridForecast)object;
				String element = gf.getElement_value();
				String filePath = rootPath + "/" + gf.getForecast_filepath();
				//读取netcdf文件数据
				GridData gridData = netcdfService.getGridDataFromNetcdf(filePath , element);
				//获取裁切之后的数据对象
				GridData rangleGridData = gridData == null ? null: getRangleGridData(gridData , rectangle2d);
				gridDatas.add(rangleGridData);
			}
			//封装需要返回的数据到对象中
			if (gridForecasts.size() > 0)
			{
				GridForecast gf = (GridForecast)gridForecasts.get(0);
				returnData = new ReturnData(gf.getOrigin_name(),  gf.getForecast_date(), gf.getForecast_sequence_name(), gf.getForecast_level_name(), gf.getElement_name(),gridDatas);
			}
		}
		catch (Exception e)
		{
			logger.error("get grid data exception , this exception is : " + e);
		}
		return returnData;
	}

	/**
	 * 
	 * @Description: 获取所有nc文件数据
	 * @return List<GridData>
	 * @throws
	 */
	private List<GridData> getGridData(String rootPath , List<Object> gridForecasts)
	{
		List<GridData> gridDatas = null;
		try
		{
			gridDatas = new ArrayList<GridData>();
			for (Object object : gridForecasts)
			{
				GridForecast gf = (GridForecast)object;
				String element = gf.getElement_value();
				
				String filePath = rootPath + "/" + gf.getForecast_filepath();
				//对"风"要素进行特殊处理
				if ("EDA10".equals(element))
				{
					gridDatas.addAll(this.getWindUV(filePath));
				}
				else {
					//读取netcdf文件数据
					GridData gridData = netcdfService.getGridDataFromNetcdf(filePath , element);
					//获取裁切之后的数据对象
					gridDatas.add(gridData);
				}
				
			}
			
		}
		catch (Exception e)
		{
			logger.error("get grid data exception , this exception is : " + e);
		}
		return gridDatas;
	}

	private List<GridData> getWindUV(String filePath)
	{
		List<GridData> gridDatas = null; 
		try
		{
			gridDatas = new ArrayList<GridData>();
			String elementV = "VEDA10";  //风V
			String elementU = "UEDA10";  //风U
			
			GridData gridDataV = netcdfService.getGridDataFromNetcdf(filePath , elementV);
			GridData gridDataU = netcdfService.getGridDataFromNetcdf(filePath , elementU);
			
			//计算风速
			float[][] datasV = gridDataV.getValues();
			float[][] datasU = gridDataU.getValues();
			//风V--垂直方向
			//风U--水平方向
			int rows = datasU.length;
			int clos = datasU[0].length;
			float[][] windSpeeds = new float[rows][clos];//风速数组
			float[][] WindDirections = new float[rows][clos];//风向数组
			for (int i = 0; i < rows; i++)	//行
			{
				for (int j = 0; j < clos; j++)//列
				{
					float x = datasU[i][j];
					if (Float.isNaN(x) || Float.isNaN(x))
					{
						x = 0f;
					}
					float y = datasV[i][j];
					if (Float.isNaN(y) || Float.isNaN(y))
					{
						y = 0f;
					}
					
					float speed = DataFormatUtil.formatFloat(Math.sqrt(x * x + y * y), 2);
					double direction = 0f;
					//风向以"正北"方向为0°，顺时针
					//风向是风吹来的方向
					if (x >= 0f && y >= 0f){//第一象限
						direction = Math.toDegrees(Math.atan(y / x));
						direction = 90 - direction;
					}
					else if(x < 0f && y >= 0f){//第二象限
						direction = Math.toDegrees(Math.atan(y / x));
						direction = 90 - direction;
					}
					else if (x < 0f && y <= 0f)//第三象限
					{
						direction = Math.toDegrees(Math.atan(y / x));
						direction = 180 + direction;
					}
					else {//第四象限
						direction = Math.toDegrees(Math.atan(y / x));
						direction = 270 - direction;
					}
					windSpeeds[i][j] = speed;
					if (Double.isInfinite(direction) || Double.isNaN(direction))
					{
						WindDirections[i][j] = 0f;
					}
					else {
						WindDirections[i][j] = DataFormatUtil.formatFloat(direction, 2);
					}
				}
			}
			gridDataV.setValues(windSpeeds);
			gridDataU.setValues(WindDirections);
			gridDatas.add(gridDataV);
			gridDatas.add(gridDataU);
		}
		catch (Exception e)
		{
			logger.error( filePath + "Wind elements handle exception , this exception is : " + e);
		}
		return gridDatas;
		
	}

	/**
	 * 
	 * @Description: 获取裁切之后的对象
	 * @return GridData
	 * @throws
	 */
	private GridData getRangleGridData(GridData gridData,Rectangle2D rectangle2d)
	{
		GridData rangleGridData = null;
		try
		{
			Rectangle2D rectangle = new Rectangle2D.Float(gridData.getStartLon(), gridData.getStartLat(), DataFormatUtil.formatFloat(gridData.getEndLon() - gridData.getStartLon(), 2), DataFormatUtil.formatFloat(gridData.getEndLat() - gridData.getStartLat(), 2));
			if (rectangle.contains(rectangle2d))
			{
				if (rectangle.equals(rectangle2d))
				{
					rangleGridData = gridData;
				}
				else
				{
					// 计算裁切之后的行列数
					int rows = (int)DataFormatUtil.formatFloat(rectangle2d.getHeight() / gridData.getLatResolution(), 0) + 1; 
					int cols = (int)DataFormatUtil.formatFloat(rectangle2d.getWidth() / gridData.getLonResolution(), 0) + 1; 
					//计算裁切之后的行列起始index
					int startX = (int)DataFormatUtil.formatFloat((rectangle2d.getX() - rectangle.getX()) / gridData.getLonResolution() , 0);
					int startY = (int)DataFormatUtil.formatFloat((rectangle2d.getY() - rectangle.getY()) / gridData.getLatResolution(), 0);
					float[][]  rangleData = DataFormatUtil.getRangleData(gridData.getValues() , rows , cols , startX , startY);
					
					rangleGridData = new GridData(gridData.getElement() ,gridData.getValid(), rows, cols, gridData.getUnit(), gridData.getLevel(), (float)rectangle2d.getX() , (float)rectangle2d.getY(), (float)(rectangle2d.getX() + rectangle2d.getWidth()) , (float)(rectangle2d.getY() + rectangle2d.getHeight()), gridData.getLonResolution(), gridData.getLatResolution(), rangleData);
				}
			}
			else
			{
				logger.error("Parameter range not included.");
			}
		}
		catch (Exception e)
		{
			logger.error("Cilpper range data exception , this exception is : " + e);
		}

		return rangleGridData;
	}

    /**
     * @return String
     * @throws
     * @Description: 获取存放文件的本地目录
     */
    private String getRootPath() {
        String rootPath = System.getProperty("user.dir") + "/ProductFile";
        Date now = new Date();
        SimpleDateFormat dd = new SimpleDateFormat("yyyyMMdd");
        String forecast_date = dd.format(now);

        // 1删除1天前临时文件
        // FileUtil.delFile(rootPath, forecast_date, 1);
        // 2下载
        // 按存放服务器分类
        rootPath = rootPath + "/" + forecast_date;
        return rootPath;
    }

	/**
	 * 通过区域范围获取站点数据
	 * @param pd
	 * @return
	 */
    public ResponseData getNafpEleGridInRectByTimeAndLevelAndValidtime(PageData pd) {
		ResponseData responseData = new ResponseData();
		ReturnData returnDatas = null;
		try {
			//获取参数

			//重新封装时效数组(查询多个时效)
			if (pd.get("forecast_valid") != null) {
				String[] valids = pd.getString("forecast_valid").split(",");
				pd.put("forecast_valid", valids);
			}
			//获取传入的范围参数 重新组织
			String maxLon = pd.getString("maxLon");
			String minLon = pd.getString("minLon");
			String maxLat = pd.getString("maxLat");
			String minLat = pd.getString("minLat");

			Rectangle2D rectangle2d = new Rectangle2D.Float(Float.valueOf(minLon), Float.valueOf(minLat), DataFormatUtil.formatFloat(Float.valueOf(maxLon) - Float.valueOf(minLon), 2), DataFormatUtil.formatFloat(Float.valueOf(maxLat) - Float.valueOf(minLat), 2));
			//查询数据库
			List<Object> gridForecasts = this.gridForecastService.getGridFcstByOriginElementAndValid(pd);
			//得到本地数据文件的存放路径
			String rootPath = getRootPath();

			//下载到本地
			this.loadService.loadToLocal(rootPath, gridForecasts, serverService);
			//循环读取数据(并裁切)
			returnDatas = this.getGridData(rootPath, gridForecasts, rectangle2d);

			//封装返回数据类型(json xml text)
			//暂时只返回json格式
			responseData.setStatus(1);
			responseData.setMsg("success");
			responseData.setData(JSONObject.toJSONString(returnDatas));

		} catch (Exception e) {
			logger.error("Get an arbitrary range of data exceptions , this exception is : " + e);
			responseData.setStatus(-1);
			responseData.setMsg("Gets the exception of the rectangular grid data.");
		}


		return responseData;
    }

    /**
     * 获取站点数据，可通过区域编码、站点类型、站点ID
     * @param pd
     * @return
     */
	public ResponseData getNafpEleGridInRectByTimeAndLevelAndValidAndLon(PageData pd) {
		ResponseData responseData = new ResponseData();
		try {
			//origin forecast_date elements sequence_value forecast_valid_start  forecast_valid_end  forecast_fileversion
			//获取传入参数(不能让使用者直接传初始场id，用初始场名称去后天匹配出初始场ID)

			UniObject param = ReadXML.getInstance().getParameter().clone();
			List<UniObject> params = param.getObjectsByName("origin");
			if (params == null || params.size() < 1) {
				logger.error("ZJ: The origin of the request does not exist.");
				responseData.setStatus(0);
				responseData.setMsg("The origin of the request does not exist.");
				return responseData;
			}
			UniObject originObject = params.get(0).getObjectsByName(pd.getString("origin").toUpperCase()).get(0);
			originObject.setValue("special", "");//特殊处理的要素为空，即没有特殊处理要素(特殊要素的作用是在天气现象转换的时候请求的环境要素)
			originObject.setValue("elements", pd.getString("elements"));//参数传入的要素名[单个或者多个]

			long start = System.currentTimeMillis();
			//从数据库中获取参数数据
			List<Object> gridForecasts = gridForecastService.getGridFcstByOriginElementAndValid(pd, originObject);
			long end = System.currentTimeMillis();
			System.out.println((end - start) / 1000.0 + "秒。");
			//TODO
			//得到本地数据文件的存放路径【这里没有根据本机IP和数据所在的服务器IP比较，决定是否下载，待完善】
			String rootPath = getRootPath();

			//下载到本地
			rootPath = loadService.loadToLocal(rootPath, gridForecasts, serverService);

			//解析文件
			List<GridData> gridDatas = this.getGridData(rootPath, gridForecasts);

			//根据经纬度提取单点数据
			//2.查询站点信息stationId
			List<StationInfo> stationInfos = stationInfoService.getStationInfos(pd);

			//6.解析文件并提取站点的各个要素值
			//获取到站点的要素 时效的数据
			Map<String, Map<String, List<Float>>> map = stationDataService.stationDataByGrid(stationInfos, gridDatas, ReadXML.getInstance().getEleIntervalMap());
			responseData.setData(JSONObject.toJSONString(map));
			responseData.setStatus(1);
			responseData.setMsg("SUCCESS");

		} catch (Exception e) {
			logger.error("Get grid data by station information exception , this exception is : " + e);
			responseData.setStatus(-1);
			responseData.setMsg("EXCEPTION");
		}

		return responseData;
	}

    /**
     * 获取天气现象
     * @param pd
     * @return
     */
	public ResponseData getWeatherPhenomenaResponse(PageData pd) {
		ResponseData responseData = new ResponseData();
		try {
			UniObject paramUniObject = ReadXML.getInstance().getParameter();
			//特别注意的是，共享接口在接受传参的时候禁止让使用部门直接去传初始场ID 时效ID 时次ID 层次ID

			//1.获取参数

			//这里面包含初始场Id 要素values
			List<UniObject> params = paramUniObject.getObjectsByName("origin");
			if (params == null || params.size() < 1) {
				logger.error("ZJ: The origin of the request does not exist.");
				responseData.setStatus(0);
				responseData.setMsg("The origin of the request does not exist.");
				return responseData;
			}
			//DB查询天气现象转换相关要素
			List<Object> gridForecasts = gridForecastService.getGridFcstByOriginElementAndValid(pd, params);

			//得到本地数据文件的存放路径
			String rootPath = getRootPath();

			//下载到本地
			rootPath = loadService.loadToLocal(rootPath, gridForecasts, serverService);

			//解析文件
			List<GridData> gridDatas = this.getGridData(rootPath, gridForecasts);


			//2.查询站点信息stationId
			List<StationInfo> stationInfos = stationInfoService.getStationInfos(pd);

			//6.解析文件并提取站点的各个要素值
			//获取到站点的要素 时效的数据
			Map<String, Map<String, List<Float>>> map = stationDataService.stationDataByGrid(stationInfos, gridDatas, ReadXML.getInstance().getEleIntervalMap());

			//7.根据各个要素值转换成天气现象(优先及比较   天气现象编码到文字转换)

			Map<String, Map<Integer, String>> staionAndWeather = weatherService.weatherPhenomena(map, paramUniObject, pd.getInteger("interval"));
			responseData.setStatus(1);
			responseData.setMsg("total of " + staionAndWeather.size() + " records");
			String result = JSONObject.toJSONString(staionAndWeather);
			responseData.setData(result);
			//8.返回
		} catch (Exception e) {
			responseData.setStatus(-1);
			responseData.setMsg("exception");
			logger.error("weather controller exception , this exception is : " + e);
		}

		return responseData;
	}

}
